home *** CD-ROM | disk | FTP | other *** search
- /* --------- OFFSCREEN TOYS with SAT --------- */
- /* by Ingemar Ragnemalm 1994 */
- /* ported to Think C by Charles Brunet */
-
- /* Offscreen Toys is a nice little demo I made to make a SAT-like demo with */
- /* complete source code, independent of any libraries (except Apple's). Now, */
- /* this should be easier to do with SAT, right? Well, partially so, but while */
- /* adapting it to SAT, I ran into a minor flaw that SAT had (and doesn't have */
- /* from version 2.1 and up), namely that drawing took place after moving */
- /* sprites, but before checking for collisions, which didn't look too good in */
- /* programs where sprites bounce off each other. After fixing this flaw, I */
- /* would say that the SAT version is indeed a bit better than the independent */
- /* version. The result is quite a bit faster and with asynch sound. */
- /* */
- /* As yet another SAT demo, what does it give us? */
- /* • If you wonder what it costs to have a real event loop, or good collision */
- /* handling, this demo shows that pretty well. */
- /* • Demonstrates a moveable window AND fast mode at the same time, with the */
- /* precautions that demands when moving the window. (The window mustn't be */
- /* moved outside the screen, some internal SAT variables – that you otherwise */
- /* should never care about – must be adjusted, and we must stay word-aligned to */
- /*make it work in b/w). */
- /* */
- /* I don't consider this demo final in any way. Known flaws: */
- /* • I have made some mistakes in the port-setting. Nothing fatal, I think. */
- /* FIXED. */
- /* • I don't protect the user from moving the window outside the screen, which */
- /* might be fatal when the SAT blitters are turned on. FIXED. */
- /* • Like in the "real" Offscreen Toys, there is a bug that causes sprites to */
- /* disappear for a short while, since the position gets negative. No big deal. */
- /* • The code for the marble should be separated from the main program, to make */
- /* the code easier to follow. */
- /* I'll fix those things when I find time and inspiration for it - but you are */
- /* welcome to do it if you want! */
-
- #include <SAT.h>
-
- /* --- PART 1: Variables and constants: -------------------------------------- */
-
- /* A redefined sprite record: */
- struct OTSprite {
- /* Variables that you should change as appropriate */
- short kind; /* Used for identification. >0: friend. <0 foe */
- Point position;
- Rect hotRect, hotRect2; /* Tells how large the sprite is; hotRect is */
- /* centered around origo hotRect is set by you. */
- /* hotRect2 is offset to the current position. */
- FacePtr face; /* Pointer to the Face (appearance) to be used. */
- ProcPtr task; /* Callback-routine, called once per frame. If */
- /* task=nil, the sprite is removed. */
- ProcPtr hitTask; /* Callback in collisions. */
- ProcPtr destructTask;/* Called when a sprite is disposed. (Usually nil.)*/
- RgnHandle clip; /* Clip region to be used when this sprite is drawn.*/
- /* SAT variables that you shouldn't change: */
- Point oldpos; /* The 'task' routine is not allowed to change this!*/
- SpritePtr next, prev; /* You may change them in your own sorting */
- /* routine, but be careful if you do. */
- Rect r, oldr; /* Rectangle telling where to draw. Avoid */
- /* messing with it. */
- FacePtr oldFace; /* Used by RunSAT2 */
- Boolean dirty; /* Used by RunSAT2 */
- /* Variables for internal use by the sprites. Use as you please. Edit */
- /* as necessary - this is merely a default set, enough space for most */
- /* cases - but if you change the size of the record, call SetSpriteSize */
- /* immediately after initializing (before any sprites are created)! */
- short layer; /*For layer-sorting. When not used for that, use freely.*/
- Point speed; /* Can be used for speed, but not necessarily. */
- short mode; /* Usually used for different modes and/or to */
- /* determine what image to show next. */
- Point fixedPos; /* Fixed-point position */
- long appLong; /* long for free use by the application. */
- };
- typedef struct OTSprite OTSprite;
- typedef OTSprite *OTSpritePtr;
-
- #define kAppleID 128
- #define kFileID 129
- #define kMBarHeight 20 /* We assume 20 pixels menu bar for window */
- /* sizing and dragging. */
- #define kWindID 128 /* Window resource ID */
- #define kAboutAlertID 128 /* Alert resource ID */
-
- #define kSpriteNumber 5 /* Number of moving objects */
-
- #define kWallBounce 7 /* 1/10-ths of speed kept after wallbounce */
- #define kBallDiameterSquared (32 * 32) /* Diameter 32, squared */
-
- #define patID 128
-
- #define kSleep 5 /* Real programs may modify the sleep time */
- /* depending on whether or not they are in the */
- /* front */
- /* Trap numbers */
- #define _WaitNextEvent 0xA860
- #define _GetCIcon 0xAA1E /* E.g. any Color QuickDraw routine */
- #define k32bQD 0xAB1D
- #define _SndPlay 0xA805
-
-
- Boolean gColorQDFlag; /* True if 32-bit QD exists. If not, we run */
- /* everything in b/w. */
- Boolean gHasWNE; /* True if we can use WaitNextEvent */
- Boolean gSoundFlag; /* True if we want sound. */
- Boolean gFast;
-
- Boolean gWhoa; /* True when we want to quit */
- Boolean gCollisionFlag; /* Collisions or not? */
-
- /* Menu handles */
- MenuHandle appleMenu, fileMenu;
-
- /* The window we'll be using */
- WindowPtr gWind;
-
- /* Our two offscreens: */
- /* GrafPtr offScreen, backScreen; */
-
- /* A cicn loded as a face */
- FacePtr gCicn;
- Handle kgck;
-
- /* Sprite information. In real games, I prefer making a linked list of records, */
- /* like I do in SAT, and a lot more information for each, but here we want it */
- /* *simple*. */
- /* - position: The positions in local coordinates for the window */
- /* - fixedPos: 16 times position, which gives us fixed-point numbers */
- /* - speed: Speed vectors that is added to fixedPos for every frame */
- /* - r: Rectangles used in drawing, for remembering what part of the screen to */
- /* update */
- /* Point position[kSpriteNumber], fixedPos[kSpriteNumber]; */
- /* Point speed[kSpriteNumber]; */
- /* Rect r[kSpriteNumber]; */
- /* */
- /* …but, since this now uses SAT, the linked list is built-in, so all the */
- /* variables above are in the sprite record! */
-
- /* A long that shows how big the "bowl" is (assumes circular, not oval, bowl!): */
-
- long gBowlSize;
-
- pascal void SetupMarble (OTSpritePtr);
- pascal void HandleMarble(OTSpritePtr);
- pascal void HitMarble(OTSpritePtr, OTSpritePtr);
-
- void MainLoop(void);
- void OTInit(void);
- void OTOffscreensInit(void);
-
-
- /* --- MAIN PROGRAM BODY: ---------------------------------------------------- */
- main()
- {
- OTInit(); /* General initializations */
- OTOffscreensInit(); /* Set up the offscreen grafports */
- InitCursor(); /* Set the cursor to arrow in case it isn't. */
- SATSetPortScreen(); /* The front window is a good port to use. */
-
- /* Run until quit or click in the close box. */
- do {
- SATSetPortScreen(); /* The front window is a good port to use. */
- MainLoop();
- }while (!gWhoa);
-
- /* No cleanup is necessary here. */
- /* We could DisposeGWorld, but that isn't necessary when we are quitting. */
- SATSoundShutup();
- }
-
- /* --- PART 2: Various general, reuseable routines, mostly glue: ------------- */
-
- /* BailOut: Emergency exit. We go here on most errors. Real programs report */
- /* what the problem is. You may wish to put a breakpoint in BailOut when */
- /* debugging. */
-
- // void BailOut(void)
- // {
- // SysBeep(1); /* Minimal error message. Use alert in real programs. */
- // ExitToShell();
- // }
-
-
- /* Several functions deleted since SAT handles what they do. */
-
- /* --- PART 3: Application specific routines: -------------------------------- */
-
- /* mouse clicks, keydowns, background tasks and update events: This is where */
- /* all the action is. :-) I include some empty procedures for you to fill in if */
- /* you want to use this demo as application shell. */
-
- /* Mouse click in window content */
-
- void DoMouse (Point where, long modifiers)
- {
-
- }
-
- /* Keydown. */
-
- void DoKey (char theKey, long modifiers)
- {
-
- }
-
- /* A rather boring subroutine that moves the sprites i and j away from each */
- /* other. I almost didn't want to put this in, making the demo unnecessarily */
- /* big, but I wanted decent collisions. If anyone can suggest a better (simpler)*/
- /* collision handling for circular objects, I'd be happy to put it in. I use a */
- /* line drawing algorithm for it. I'm sure there are better ways. This is of */
- /* questionable value as reuseable code - depends on your application. */
-
- /* Normal signum function (which I don't think is in the libs) */
- short Sgn(short x)
- {
- if (x > 0)
- return 1;
- else if (x < 0)
- return -1;
- else
- return 0;
- }
-
- /* I don't think this function exist in C - Charles */
- short abs(short x)
- {
- return (x > 0) ? x : -x;
- }
-
- void Separate (OTSpritePtr i, OTSpritePtr j)
- {
- Point initVector, nowVector;
- short absH, absV;
- short moveH, moveV;
- short frac = 0;
-
- initVector.h = i->position.h - j->position.h;
- initVector.v = i->position.v - j->position.v;
- absH = abs(initVector.h);
- absV = abs(initVector.v);
- moveH = Sgn(initVector.h);
- moveV = Sgn(initVector.v);
- if (!moveH) {
- if (!moveV) {
- moveV = 1;
- }
- }
- do {
- if (absH > absV) {
- i->position.h += moveH;
- j->position.h -= moveH;
- frac += absV;
- if (frac > absH) {
- i->position.v += moveV;
- j->position.v -= moveV;
- frac -= absH;
- }
- }
- else {
- i->position.v += moveV;
- j->position.v -= moveV;
- frac += absH;
- if (frac > absV) {
- i->position.h += moveH;
- j->position.h -= moveH;
- frac -= absV;
- }
- }
- nowVector.h = i->position.h - j->position.h;
- nowVector.v = i->position.v - j->position.v;
- } while(!((long)(nowVector.h * nowVector.h) + (long)(nowVector.v * nowVector.v) > kBallDiameterSquared));
-
- i->fixedPos.h = (i->position.h << 4); /* Make fixedPos by shifting in the 4 */
- i->fixedPos.v = (i->position.v << 4); /* binary "decimals" */
-
- j->fixedPos.h = (j->position.h << 4); /* Make fixedPos by shifting in */
- j->fixedPos.v = (j->position.v << 4); /* the 4binary "decimals" */
- }
-
-
- /* Split a vector (v1) into one component parallell to another vector */
- /* (direction) and one orthogonal to it. */
-
- void SplitVector(Point v1, Point direction, Point *parallell, Point *normal)
- {
- long l2, v1pr;
-
- l2 = direction.h * direction.h + direction.v * direction.v; /* Squared */
- /* length of "direction" */
- v1pr = v1.h * direction.h + v1.v * direction.v; /* Scalar product */
-
- parallell->h = direction.h * v1pr / l2;
- parallell->v = direction.v * v1pr / l2;
- normal->h = v1.h - parallell->h;
- normal->v = v1.v - parallell->v;
- }
-
- pascal void HandleMarble(OTSpritePtr i)
- {
- Point vector;
-
- /* Modify fixed-point position by speed */
- i->fixedPos.h += i->speed.h;
- i->fixedPos.v += i->speed.v;
-
- /* Make position by shifting away the 4 binary "decimals" */
- if (i->fixedPos.h >= 0)
- i->position.h = (i->fixedPos.h >> 4);
- else
- i->position.h = ((i->fixedPos.h >> 4) | 0xf000);
- if (i->fixedPos.v >= 0)
- i->position.v = (i->fixedPos.v >> 4);
- else
- i->position.v = ((i->fixedPos.v >> 4) | 0xf000);
-
- /* Outside the allowed area? */
- if (i->position.h < 0)
- i->speed.h = abs(i->speed.h) * kWallBounce / 10 + 1;
- if (i->position.v < 0)
- i->speed.v = abs(i->speed.v) * kWallBounce / 10 + 1;
- if (i->position.h + gCicn->iconMask.bounds.right > gSAT.offScreen.port->portRect.right)
- i->speed.h = -abs(i->speed.h) * kWallBounce / 10 - 1;
- if (i->position.v + gCicn->iconMask.bounds.bottom > gSAT.offScreen.port->portRect.bottom)
- i->speed.v = -abs(i->speed.v) * kWallBounce / 10 - 1;
-
- /* Are we in the bowl? If we are, accelerate towards the center. */
- vector.h = i->position.h + 16 - (gSAT.offScreen.port->portRect.right >> 1);
- vector.v = i->position.v + 16 - (gSAT.offScreen.port->portRect.bottom >> 1);
- if ((vector.h * vector.h + vector.v * vector.v) < gBowlSize) {
- i->speed.h -= vector.h / 2;
- i->speed.v -= vector.v / 2;
- }
- }
-
- pascal void HitMarble(OTSpritePtr i, OTSpritePtr j)
- {
- Point vector;
- long squaredLength;
- Point p1, p2, n1, n2, tmpSpeed;
-
- if (!gCollisionFlag)
- return;
-
- /* Find the vector between them */
- vector.h = i->position.h - j->position.h;
- vector.v = i->position.v - j->position.v;
- squaredLength = (long)(vector.h * vector.h) + (long)(vector.v * vector.v);
- /* If it is shorter than the diameter of a ball… */
- if (squaredLength < kBallDiameterSquared) {
- /* Move them away from each other */
- Separate(i, j);
-
- /* Swap the speed components that are parallell to "vector" (this allows for */
- /* "touches", very nice and realistic bounces) */
- SplitVector(i->speed, vector, &p1, &n1);
- SplitVector(j->speed, vector, &p2, &n2);
-
- j->speed.h = p1.h + n2.h;
- j->speed.v = p1.v + n2.v;
-
- i->speed.h = p2.h + n1.h;
- i->speed.v = p2.v + n1.v;
-
- /* Old Offscreen Toys just swapped the speed, as commented out below. This is */
- /* not as realistic. */
- /* tmpSpeed = i->speed; */
- /* i->speed = j->speed; */
- /* j->speed = tmpSpeed; */
-
- /* Play a sound. SAT is good at playing sounds! */
- if (gSoundFlag)
- SATSoundPlay(kgck, 1, false);
- }
- }
-
- pascal void SetupMarble(OTSpritePtr i)
- {
- i->fixedPos.h = (i->position.h << 4);
- i->fixedPos.v = (i->position.v << 4);
- i->speed.h = Random() % 32;
- i->speed.v = Random() % 32;
- i->task = (ProcPtr)&HandleMarble;
- i->hitTask = (ProcPtr)&HitMarble;
- i->face = gCicn;
- SetRect(&(i->hotRect), 0, 0, 32, 32);
- }
-
- /* A little routine for setting the forecolor with a single line. */
-
- void OTForeColor(short red, short green, short blue)
- {
- RGBColor theColor;
-
- theColor.red = red;
- theColor.green = green;
- theColor.blue = blue;
- RGBForeColor(&theColor);
- }
-
- void DrawBackground(void)
- {
- /* A static variable only used in DrawBackground */
- static PixPatHandle thePat;
- Rect r;
- Boolean mycolorFlag;
- SATPort savePort;
-
- /* DrawBackground */
- SATGetPort(&savePort);
- SATSetPortBackScreen();
- /* Do some drawing in backScreen. First, we paint a pattern (using a */
- /* 'ppat' resource): */
-
- /* For drawing the background, let's make a local flag that tells us if */
- /* we shold draw b/w patterns or color ones. */
- if (gColorQDFlag)
- mycolorFlag = gSAT.initDepth > 1;
- else
- mycolorFlag = false;
-
- if (mycolorFlag) {
- if (thePat == NULL)
- thePat = GetPixPat(patID);
- PenPixPat(thePat);
- }
- else {
- if (thePat == NULL)
- thePat = (PixPatHandle)GetResource('ppat', patID);
- PenPat(&(*thePat)->pat1Data);
- }
- PaintRect(&gSAT.backScreen.port->portRect);
- PenNormal();
-
- /* Then we draw some circles. */
-
- r = gSAT.backScreen.port->portRect;
- InsetRect(&r, (r.right - r.left) / 8, (r.bottom - r.top) / 8);
- /* Tells how big the "bowl" is! */
- gBowlSize = (long)(r.right - r.left) * (long)(r.right - r.left) / 4;
- if (mycolorFlag) {
- OTForeColor(-10000, -10000, -10000);
- PaintOval(&r);
- }
- else
- FillOval(&r, &qd.ltGray);
-
- InsetRect(&r, (r.right - r.left) / 8, (r.bottom - r.top) / 8);
- if (mycolorFlag) {
- OTForeColor(-25000, -25000, -25000);
- PaintOval(&r);
- }
- else
- FillOval(&r, &qd.gray);
-
- InsetRect(&r, (r.right - r.left) / 6, (r.bottom - r.top) / 6);
- if (mycolorFlag) {
- OTForeColor(20000, 20000, 20000);
- PaintOval(&r);
- }
- else
- FillOval(&r, &qd.dkGray);
-
- InsetRect(&r, (r.right - r.left) / 5, (r.bottom - r.top) / 5);
- if (gSAT.colorFlag)
- OTForeColor(0, 0, 0);
- PaintOval(&r);
-
- SATSetPortOffScreen();
- CopyBits(&gSAT.backScreen.port->portBits, &gSAT.offScreen.port->portBits, &gSAT.backScreen.port->portRect, &gSAT.backScreen.port->portRect, srcCopy, NULL);
-
- SATSetPort(&savePort);
- }
-
- /* DoBackground: repeating tasks - this is called repeatedly, after every event */
- /* we get. */
-
- /* Note: If you are making a really Mac-friendly program, this is where you */
- /* should drive the animation. However, it is hard to get high framerate then, */
- /* since other programs (the Finder included) will process events which will */
- /* make it less smooth. */
-
- void DoBackground(void)
- {
- Rect tmpRect;
- short i, j;
- Point vector;
- GDHandle saveGD;
- GrafPtr savePort;
- Point tmpSpeed;
-
- SATRun(gFast); /* Eller konfigurerbart? */ /* What? - Charles */
- }
-
- /* DoUpdate: handle update events, in this case by copying offScreen to the */
- /* screen (gWind). */
-
- /* Note to beginners: A program without update events processing is not a real */
- /* Mac program! All drawing you do must reach the update event handler in some */
- /* way, or it might be lost, or worse, partially erased, which is really ugly. */
-
- void DoUpdate(void)
- {
- GDHandle saveGD;
- GrafPtr savePort;
-
- if (SATDepthChangeTest())
- DrawBackground();
- BeginUpdate(gWind);
- SATRedraw();
- EndUpdate(gWind);
- }
-
- /* DoAppleMenu and DoFileMenu: handle menu selections */
-
- void DoAppleMenu (short item)
- {
- Str255 str;
- Handle h;
- SATPort savePort;
- short ignore;
-
- if (item == 1) {
- if (Alert(kAboutAlertID, nil) == 1)
- ; /* Ignore result */
- }
- else {
- /* Apple menu other than "About": Code from TransSkel */
- SATGetPort(&savePort);
- GetItem(appleMenu, item, str);
- SetResLoad(false);
- h = GetNamedResource('DRVR', str);
- SetResLoad(true);
- if (h != NULL) {
- ReserveMem(SizeResource(h) + 0x1000);
- /* Old intf: ResrvMem, SizeResource */
- ignore = OpenDeskAcc(str);
- }
- SATSetPort(&savePort);
- }
- }
-
- void DoFileMenu (short item)
- {
- long start, finish, frames;
-
- Str255 str1, str2 = "\p frames/second";
-
- switch (item) {
- case 1:
- /* Run animation without event processing until the user clicks the mouse */
- /* Note: This runs the animation at maximum speed. In real programs, we must */
- /* limit the speed with the system clock, e.g. inspect TickCount. */
- start = TickCount();
- frames = 0;
- while (!Button()) {
- DoBackground();
- frames++;
- }
- finish = TickCount();
- /* Concat two strings -- Charles */
- NumToString(frames * 60 / (finish - start), str1);/* convert to Str255*/
- BlockMove(&str2[1], &str1[str1[0] + 1], str2[0]); /* concat */
- str1[0] += str2[0]; /* Add number of char */
- SATReportStr(str1);
- break;
-
- case 2:
- gCollisionFlag = !gCollisionFlag;
- CheckItem(fileMenu, 2, gCollisionFlag);
- break;
-
- case 3:
- gFast = !gFast;
- CheckItem(fileMenu, 3, gFast);
- break;
-
- case 4:
- gSoundFlag = !gSoundFlag;
- CheckItem(fileMenu, 4, gSoundFlag);
- break;
-
- /* Set the flag that tells the program to quit. */
- case 6:
- gWhoa = true;
- }
- }
-
- /* --- PART 4: Event processing: --------------------------------------------- */
-
- /* MenuSelection: Menu selection by mouse or command-key: */
-
- void MenuSelection (long whatSelection)
- {
- switch (HiWord(whatSelection)) {
- case kAppleID:
- DoAppleMenu(LoWord(whatSelection));
- break;
-
- case kFileID:
- DoFileMenu(LoWord(whatSelection));
- break;
- }
- HiliteMenu(0);
- }
-
- /* MainLoop: get and process events. This is the boring standard part of all */
- /* programs. I prefer using TransSkel to get rid of it. I don't here since I */
- /* want this code to be stand-alone. */
-
- void MainLoop(void)
- {
- Boolean hasEvent;
- EventRecord theEvent;
- char theKey;
- long whatSelection;
- short whichPart;
- WindowPtr whichWindow;
- Rect r;
- Point p, pt = {0x0040, 0x0040};
-
- /* Get the next event. Use WaitNextEvent if possible. */
- if (gHasWNE)
- hasEvent = WaitNextEvent(everyEvent, &theEvent, kSleep, NULL);
- else {
- SystemTask();
- hasEvent = GetNextEvent(everyEvent, &theEvent);
- }
-
- /* OK, so what happened then? */
- if (hasEvent) {
- switch (theEvent.what) {
- case mouseDown:
- whichPart = FindWindow(theEvent.where, &whichWindow);
- switch (whichPart) {
- case inMenuBar:
- whatSelection = MenuSelect(theEvent.where);
- MenuSelection(whatSelection);
- break;
-
- case inSysWindow:
- SystemClick(&theEvent, whichWindow);
- break;
-
- case inGoAway:
- if (TrackGoAway(whichWindow, theEvent.where))
- gWhoa = true;
- break;
-
- case inDrag:
- if ((whichWindow != FrontWindow()) && (!(theEvent.modifiers & cmdKey)))
- SelectWindow(whichWindow);
- r = gSAT.bounds; /* How big is the screen? */
- r.top += kMBarHeight; /* Skip down past menu bar */
- InsetRect(&r, 4, 4);
-
- /* LIMIT THE DRAGGING so no part of the window can get outside the screen! Cut */
- /* down on r depending on where the click is? This is necessary if we use "fast */
- /* mode", that is if we do SATRun(true) or any other operation with custom */
- /* blitters. */
- SetPort(whichWindow);
- p = theEvent.where;
- GlobalToLocal(&p);
- r.bottom -= (whichWindow->portRect.bottom - p.v);
- r.left += p.h;
- r.right -= (whichWindow->portRect.right - p.h);
-
- DragWindow(whichWindow, theEvent.where, &r);
-
- if (whichWindow == gSAT.wind.port)
- SATWindMoved();
- break;
-
- case inGrow:
- break; /* Ignored - we don't resize */
-
- case inContent:
- if (whichWindow != FrontWindow())
- SelectWindow(whichWindow);
- else
- /* Go to application-specific mouse down handling */
- DoMouse(theEvent.where, theEvent.modifiers);
- break;
- }
- break;
-
- case keyDown:
- case autoKey:
- theKey = (char)(theEvent.message & charCodeMask);
- if (theEvent.modifiers & cmdKey)
- MenuSelection(MenuKey(theKey));
- else
- DoKey(theKey, theEvent.modifiers);
- break;
-
- case updateEvt:
- /* There's only one window to bother with here, but let's make sure that's the */
- /* one the Mac wants to update. */
- if ((WindowPtr)theEvent.message == gWind)
- DoUpdate();
- /* Handle disk inserts like TransSkel. */
- case diskEvt:
- if (HiWord(theEvent.message) != noErr) {
- DILoad();
- if (!DIBadMount(pt, theEvent.message))
- ;
- DIUnload();
- }
- }
- }
- DoBackground();
- }
-
- /* --- PART 5: Initializations: ----------------------------------------- */
-
- /* OTInit: Initialize global flags, menus and window */
-
- void OTInit(void)
- {
- SATInitToolbox();
-
- gHasWNE = SATTrapAvailable(_WaitNextEvent);
- gColorQDFlag = SATTrapAvailable(k32bQD) && SATTrapAvailable(_GetCIcon); /* ??? */
- gWhoa = false;
- gCollisionFlag = false;
-
- gSoundFlag = true;
-
- /* What more should I check for? Check with Gestalt instead? */
-
- qd.randSeed = TickCount(); /* Seed the random number generator - TickCount */
- /* is good enough. */
-
- /* Get the window, a color window if we are going to use color. */
- if (gColorQDFlag)
- gWind = GetNewCWindow(kWindID, NULL, (WindowPtr)-1);
- else
- gWind = GetNewWindow(kWindID, NULL, (WindowPtr)-1);
-
- /* Some menus. We could read these from resources. */
- appleMenu = NewMenu(kAppleID, "\p\024");
- AppendMenu(appleMenu, "\pAbout Offscreen Toys SAT…;(-");
- AddResMenu(appleMenu, 'DRVR'); /* Old intf: AddResMenu */
- InsertMenu(appleMenu, 0); /* put apple menu at end of menu bar */
- fileMenu = NewMenu(kFileID, "\pFile");
- AppendMenu(fileMenu, "\pTry max speed;Collisions;Use SAT blitters;Use sound;(-;Quit/Q");
- InsertMenu(fileMenu, 0); /* put file menu at end of menu bar */
- DrawMenuBar();
- CheckItem(fileMenu, 4, gSoundFlag);
- }
-
- /* OTOffscreensInit: Initialize offscreen grafports (worlds) and draw in them. */
-
- void OTOffscreensInit(void)
- {
- SATPort savePort;
- Rect r;
- short i;
- SpritePtr sp;
-
- SATConfigure(false, kNoSort, kForwardOneCollision, 32); /* Only call *one* */
- /* hitTask, not both. */
- SATCustomInit(0, 0, &gWind->portRect, gWind, NULL, false, false, false, true, false);
-
- DrawBackground();
-
- /* Done drawing! */
- /* For your own hacks, consider using a PICT resource and use GetPicture and */
- /* DrawPicture to draw the background. Note that you'll need both a color and */
- /* a b/w picture if you want it to look good in b/w. */
-
- SATSetPortScreen();
-
- /* Get the cicn resource */
- /* Note: You can, of course, use several cicns and switch between. */
- gCicn = SATGetFace(128);
- kgck = SATGetNamedSound("\pKgck");
-
- /* Initialize the sprites: */
-
- for (i = 1; i <= kSpriteNumber; i++)
- sp = SATNewSprite(1, SATRand(gSAT.offScreen.port->portRect.right - 32), (i - 1) * (gSAT.offScreen.port->portRect.bottom - 32) / 5 + SATRand((gSAT.offScreen.port->portRect.bottom - 32) / 5), (TaskPtr)&SetupMarble);
-
- if (SATSoundInitChannels(2) < 2)
- SysBeep(1);
- }